package com.localsocial.screenphone;

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import oauth.signpost.OAuth;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;

import com.localsocial.Device;
import com.localsocial.LocalSocial;
import com.localsocial.LocalSocialFactory;
import com.localsocial.Platform;
import com.localsocial.config.SimpleAppConfiguration;
import com.localsocial.ds.Person;
import com.localsocial.model.RemoteDevice;
import com.localsocial.model.Tag;
import com.localsocial.oauth.AccessToken;
import com.localsocial.oauth.OAuthConsumer;
import com.localsocial.oauth.RequestToken;
import com.localsocial.oauth.Verifier;
import com.localsocial.proximity.PeriodicScan;
import com.localsocial.proximity.observers.NeighbourhoodObserver;
import com.localsocial.remote.RemoteFactory;
import com.localsocial.remote.exception.ParseException;
import com.localsocial.remote.exception.UnauthorizedException;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.Instrumentation;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;
import android.widget.ViewSwitcher;
import android.widget.TextView;
import android.widget.Toast;

import android.net.ConnectivityManager;

public class ScreenPhone extends Activity {
		
	private final String TAG = getClass().getName();
	private final int BT_ON = 1;
	private static final boolean D = true;	
	
	private SharedPreferences prefs;
	
	public static LocalSocial m_localsocial;
	public static String m_local_mac;
	public static AccessToken m_access_token;
	private OAuthConsumer m_consumer;
	private PeriodicScan m_scan;
	private String m_address = null;
	private RemoteFactory m_remote;
	private HashMap<String,RemoteDevice> m_devices = new HashMap<String,RemoteDevice> ();
	private Map<String, Device> m_seen = new HashMap<String, Device>();
	
	private SimpleAppConfiguration m_sac = new SimpleAppConfiguration();
    private Platform m_platform = new Platform();
	
	private LinkedInAPICall linkedIn;
	private List<Person> people = new LinkedList<Person>();
	private List<Person> user_connections = new LinkedList<Person>();
	private List<Person> possible_connections = new LinkedList<Person>();
	private List<Person> to_display = new LinkedList<Person>();
	private ViewSwitcher switcher;
	private GridView grid_view;
	private String curr_view = "";
	private ImageAdapter image_adapter;
	private String user_name = "";
	
	private BluetoothService bluetooth_service = null;
	private static final int DIALOG_CONNECTION_REQUIRED = 0;
	private static final int DIALOG_LINKEDIN_OAUTH = 1;
	private static final int DIALOG_LINKEDIN_AUTH_ERROR = 2;
	private static final int DIALOG_GREETING = 3;
	
    public static final String DEVICE_NAME = "device_name";
    public static final String TOAST = "toast";
    
    public static final int MESSAGE_STATE_CHANGE = 1;
    public static final int MESSAGE_READ = 2;
    public static final int MESSAGE_WRITE = 3;
    public static final int MESSAGE_DEVICE_NAME = 4;
    public static final int MESSAGE_TOAST = 5;
    public static final int MESSAGE_KEY_SEND = 6;
        
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        TextView textView = (TextView) findViewById(R.id.company_text);
    	textView.setText(Constants.ABOUT_COMPANY);
    	
    	switcher = (ViewSwitcher) findViewById(R.id.profileSwitcher);
        
        this.prefs = PreferenceManager.getDefaultSharedPreferences(this);
        
        // instance for making linkedin API calls
        linkedIn = new LinkedInAPICall(this, "reg");
    	
    	// clear the list before loading
    	people.clear();
 	
    	// Bluetooth
    	BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    	if (mBluetoothAdapter == null) {
    		// Device does not support Bluetooth. End the activity.
    		ScreenPhone.this.finish();
    	} else {
    		// enable Bluetooth if is not
    		if (!mBluetoothAdapter.isEnabled()) {
    		    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    		    // if BT_ON >=0 
    		    startActivityForResult(enableBtIntent, BT_ON);
    		}
    	}
    	
    	// check if a device is connected to a network
    	if (isOnline()) {
    		Log.i(TAG, "CONNECTED"); 
    		
    		// LocalSocial
    		m_localsocial = configureLocalSocial();
    		m_localsocial.getNeighbourhood().observeNeighbourhood(getNeighbourhoodObserver());
            m_remote = m_localsocial.getRemoteFactory();
			doLocalSocialOAuth();
			
			// LinkedIn		
    		showDialog(DIALOG_LINKEDIN_OAUTH);
    		retrieveConnections();
    	} else {
    		Log.i(TAG, "NOT CONNECTED");    		
    		showDialog(DIALOG_CONNECTION_REQUIRED);
    	}
    	
    	// if configured, start scan
    	if (m_localsocial != null) {
    		startScan();
    	}
    	
    	
    	grid_view = (GridView) findViewById(R.id.grid_view);
    	image_adapter = new ImageAdapter(this, people);
    	grid_view.setAdapter(image_adapter); 
    	
    	/**
    	 * OnItemClickListener for grid view
    	 */
    	grid_view.setOnItemClickListener(new OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
                // Toast.makeText(ScreenPhone.this, "Selected position: " + position, Toast.LENGTH_SHORT).show();
            	
                String selectedProfileRequest = Constants.PROFILE_REQUEST 
                		+ people.get(position).getID() + Constants.PROFILE_FIELDS;
                
                String jsonOutput = linkedIn.execute(selectedProfileRequest);                
                Log.d("Profile", "json = " + jsonOutput);
                parseJsonProfile(jsonOutput);
                
                if (!curr_view.equals("web")) {
                	switcher.showNext();
                	curr_view = "web";
                }
            }
        });  	
    	
    	// BluetoothService
    	bluetooth_service = new BluetoothService(this, mHandler);
    	bluetooth_service.start();
    }
    
    
    /**
     * Called when activity is resumed
     */
    @Override
    public void onResume() {
    	super.onResume();
    	Log.i("STATE", "OnResume");
    }
    
    /**
     * Called when activity is restarted
     */
    @Override
    public void onRestart() {
    	super.onRestart();
    	Log.i("STATE", "OnRestart");
    }
    
    /**
     * This is the final call before activity is destroyed
     */
    @Override
    public void onDestroy() {
    	Log.i("STATE", "onDestory");
        image_adapter.imageLoader.stopThread();
        grid_view.setAdapter(null);
        
        people.clear();
        
        // clear image cache
        image_adapter.imageLoader.clearCache();
        image_adapter.notifyDataSetChanged();
        super.onDestroy();
    }
    
    /**
     * Called whenever the activity is hidden
     */
    @Override
    protected void onStop() {
        Log.i("STATE", "onStop");
        super.onStop();
        if (m_localsocial != null) {
            stopScan();
            Log.d(TAG, "removing neighbourhood observer");
            m_localsocial.getNeighbourhood().removeObserver(getNeighbourhoodObserver());
        }
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu, menu);
        return true;
    }
    
    
    /**
     * This method is called when back key is pressed
     */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event)  {
        if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {

            switcher.showPrevious();

            return true;
        }

        return super.onKeyDown(keyCode, event);
    }
    
    public LocalSocial.Configuration getConfig() {
        return m_localsocial.getConfig();
    }
    
    public String getAddress() {
        if (m_address == null) {
            m_address = getConfig().getAddress();
            if (m_address == null) {
                m_address = m_localsocial.getNeighbourhood().getAddress();
            }
        }
        return m_address;
    }
    

    
    protected LocalSocial configureLocalSocial() {    	
    	m_sac = new SimpleAppConfiguration();    	
    	m_sac.setServiceName(Constants.LS_NAME);
    	m_sac.setConsumerKey(Constants.LS_KEY);
        m_sac.setConsumerSecret(Constants.LS_SECRET);
        m_sac.setAuthCallback(Constants.LS_CALLBACK);
        
        m_platform = new Platform();        
        m_platform.setContext(getApplication());
        
        m_sac.setPlatformContext(m_platform);        
        LocalSocialFactory.setDefaultConfig(m_sac);
        
        return LocalSocialFactory.getLocalSocial();        
    }
    
    /**
     * Stop the current periodic scan
     */
    protected void stopScan() {    	
        if (m_scan != null) {
            Log.d(TAG, "stop scan");
            m_scan.stop();
            m_scan = null;
            Log.i(TAG, "Scan is stopped");
        } else {
            Log.d(TAG, "not scanning");
        }
    }

    /**
     * Start a new scan
     */
    protected void startScan() {
    	Log.i(TAG, "Starting scan");
        m_scan = m_localsocial.getNeighbourhood().startScan();
        if (m_scan == null) {
        	Log.w("TAG", "scan is null");
        }
    }

    /**
     * Stop the current scan if there is one and then start a new one
     */
    protected void restartScan() {
    	Log.i(TAG, "Restarting scan");
        stopScan();
        startScan();
    }
    
    
    
    
    /**
     * Callback method for dialogs
     * @return 
     */
    public Dialog onCreateDialog(int id) {
    	Dialog dialog;
    	
    	switch (id){
    	case DIALOG_CONNECTION_REQUIRED:
    		AlertDialog.Builder builder_connection = new AlertDialog.Builder(this);
    		builder_connection.setMessage("Sorry, this application requries network connection." +
    				"Connect to a network and restart the application.")
    		       .setCancelable(false)
    		       .setPositiveButton("OK", new DialogInterface.OnClickListener() {
    		           public void onClick(DialogInterface dialog, int id) {
    		                ScreenPhone.this.finish();
    		           }
    		       });
    		dialog = builder_connection.create();
    		break;
    	case DIALOG_LINKEDIN_OAUTH:
    		final View view = getWindow().getDecorView().findViewById(android.R.id.content);
    		
    		AlertDialog.Builder builder_oauth = new AlertDialog.Builder(this);
    		builder_oauth.setMessage("Please Authenticate with LinkedIn")
    		       .setCancelable(false)
    		       .setPositiveButton("OK", new DialogInterface.OnClickListener() {
    		           public void onClick(DialogInterface dialog, int id) {
    		        	   startActivityForResult(new Intent().setClass(view.getContext(), PrepareRequestToken.class), 2);
    		           }
    		       })
    		       .setNegativeButton("Back", new DialogInterface.OnClickListener() {
    		           public void onClick(DialogInterface dialog, int id) {
    		        	   dialog.cancel();
    		           }
    		       });
    		dialog = builder_oauth.create();
    		break;
    	case DIALOG_LINKEDIN_AUTH_ERROR:
    		AlertDialog.Builder builder_auth_error = new AlertDialog.Builder(this);
    		builder_auth_error.setMessage("LinkedIn authorisation error." +
    				"Please start the application again and authorise with LinkedIn.")
    		       .setCancelable(false)
    		       .setPositiveButton("OK", new DialogInterface.OnClickListener() {
    		           public void onClick(DialogInterface dialog, int id) {
    		                ScreenPhone.this.finish();
    		           }
    		       });
    		dialog = builder_auth_error.create();
    		break;
    	case DIALOG_GREETING:
    		AlertDialog.Builder builder_greet = new AlertDialog.Builder(this);
    		builder_greet.setMessage("Hello, " + user_name + "! \n" +
    				"Please start the Phone/Screen application to connect to the Screen.")
    		       .setCancelable(false);
    		dialog = builder_greet.create();
    		break;
    	default:
    		dialog = null;
    	}  	
    			
		return dialog;   	
    }
    
    /**
     * This method is a callback for enableBTintent
     */
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {    	
    	
        if (resultCode == 0) {
        	Log.i(TAG, "BT was enabled");
        	m_localsocial = configureLocalSocial();
        	doLocalSocialOAuth();            
        } else if (resultCode == 2) {
        	m_localsocial = configureLocalSocial();    		
			doLocalSocialOAuth();
			
        	if (m_localsocial != null) {
        		startScan();
        	}
        }
     
        
        // doLocalSocialOAuth();
    }
    
    /**
     * Authenticate with LocalSocial
     */
    public void doLocalSocialOAuth() {
		if (m_localsocial != null) {
			Log.i(TAG, "LOCAL SOCIAL INITIALISED");
			Log.i(TAG, "Starting OAuth");
	        m_consumer = m_localsocial.getOAuthConsumer();
	        m_access_token = null;
	        
	        try {
	        	m_access_token = m_localsocial.loadAccessToken();
	        	Log.i(TAG, "Using existing token");
	        } catch (UnauthorizedException e) {
	        	Log.i(TAG, "No token");
	        	Log.i(TAG, m_localsocial.toString());
	        	RequestToken token = null;
	        	
	        	try {
	        		 token = m_consumer.generateRequestToken();
	        		 Verifier verifier = m_consumer.authorise(token);
	        		 m_access_token = m_consumer.exchange(token, verifier);
	        		 m_localsocial.saveAccessToken(m_access_token);
	        		 Log.i(TAG, "New token generated");
	        	} catch (UnauthorizedException unauth) {
	        		Log.i(TAG, "Unauthorized Exception", unauth);
	        	} catch (IOException io) {
					Log.i(TAG, "IO Exception", io);
				}   		        	
	        }
		} else {
			Log.i(TAG, "LOCAL SOCIAL NULL");
		}
    }
    
    
    /**
     * This method does LinkedIn API call
     */
    public void retrieveConnections() {    	
    	String jsonOutput = linkedIn.execute(Constants.CONNECTIONS_REQUEST);    	
    	parseJsonConnections(jsonOutput);
    }
    
	/**
	 * Parse json output for connections API call
	 */
    public void parseJsonConnections(String jsonOutput) {
    	try {
    		Log.d("JSON", jsonOutput);
    		
			// json object creation
			JSONObject json = new JSONObject(jsonOutput);
			// json parsing
			JSONArray nameArray = json.names();
			JSONArray valArray = json.toJSONArray(nameArray);
			
			
			JSONArray connections = valArray.getJSONArray(1);
			// for each person
			for (int i=0; i< connections.length(); i++) {				
				JSONObject object = (JSONObject) new JSONTokener(connections.getString(i)).nextValue();
				String id = object.getString("id");
				String firstName = object.getString("firstName");
				String lastName = object.getString("lastName");			
				String pictureUrl = "";
				try {
					 pictureUrl = object.getString("pictureUrl");
				} catch (Exception noProfilePic) {
					pictureUrl = "noPicture";
				}
				
				Person person = new Person(id, firstName, lastName, pictureUrl);
				people.add(person);
				Log.i("PERSON", person.toString());
				Log.d("JSON", "url = "+person.getPictureUrl());
			}			
		} catch (JSONException e) {
			Log.d("JSON", "Error creating json object");
			showDialog(DIALOG_LINKEDIN_AUTH_ERROR);
			Log.e(TAG, "Error creating json object",e);
		}
		
		// temp
		
		grid_view = (GridView) findViewById(R.id.grid_view);
    	image_adapter = new ImageAdapter(this, people);
    	grid_view.setAdapter(image_adapter);
    }
    
    /**
	 * Parse json output for profile API call
	 */
    public void parseJsonProfile(String jsonOutput){
    	try {
			JSONObject json = (JSONObject) new JSONTokener(jsonOutput).nextValue();
			JSONArray nameArray = json.names();
			JSONArray valArray = json.toJSONArray(nameArray);
			
			String firstName = json.getString("firstName");
			String lastName = json.getString("lastName");
			String headline = json.getString("headline");
			String summary = " ", specialties = " ";
			try {
				summary = json.getString("summary");
				specialties = json.getString("specialties");
			} catch (JSONException noValue) {
			}
			String numberOfConnections = json.getString("numConnections");
			
			TextView name_view = (TextView) findViewById(R.id.person_name);
			name_view.setText(firstName + " " + lastName);
			
			TextView headline_view = (TextView) findViewById(R.id.person_headline);
			headline_view.setText(headline);
			
			TextView connections_view = (TextView) findViewById(R.id.person_connections);
			connections_view.setText("Number of connections: " + numberOfConnections);
			
			TextView summary_view = (TextView) findViewById(R.id.person_summary);
			summary_view.setText("Summary: " + summary);
			
			TextView specialities_view = (TextView) findViewById(R.id.person_specialities);
			specialities_view.setText("Specialties: " + specialties);
			
			
			Log.d("Profile", nameArray.toString());
			Log.d("Profile", valArray.toString());
			
			Log.d("Profile", "Name: " + firstName + " " + lastName);
			Log.d("Profile", "Headline: " + headline);
			Log.d("Profile", "NumOfConnections: " + numberOfConnections);
			Log.d("Profile", "Summary: " + summary);
			Log.d("Profile", "Specialties: " + specialties);
			
		} catch (JSONException e) {
			Log.d("Profile", e.toString());
		}
    }
	
    
    /**
     * Called when a device is found during the scan
     */
    public void deviceFound(Device d) {
    	String devices = "";
    	for (Device device: m_seen.values()){
    		devices += ", " + device.getName()+" "+device.getAddress();
    	}
        
    	Log.i("DEVICES", "DEVICE FOUND " + d.getName() + ", address = " + d.getAddress());
        
        // set a tag on it (tag name, this device's bt mac address, target)                 
        setTag(Constants.LS_TAB_MAC_ADDR_TAG, getAddress(), d.getAddress());
        
        // retrieve all tags associated with this device
        getAllTags(d.getAddress());
    }
    
    /**
     * Create new tag task
     * @param namespace
     * @param name
     * @param value
     * @param target
     * @return 
     */
    public SetTagTask setTag(String name, String value, String target) {
        SetTagTask task = new SetTagTask();
        task.execute(Constants.LS_NAMESPACE, name, value, target);
        return task;
    }
    
    /**
     * Update or create tag
     */
    class SetTagTask extends AsyncTask<String, Void, Exception> {
        String namespace;
        String name;
        String value;
        String target;

        @Override
        protected Exception doInBackground(String... params) {
            namespace = params[0];
            name = params[1];
            value = params[2];
            target = params[3];
            
            Exception e = null;
            try {
                m_remote.getTagRemote().updateOrCreate(namespace, name, value, target);
            } catch (Exception ex) {
                e = ex;
            }
            return e;
        }

        protected void onPostExecute(Exception e) {
            if (e == null) {
                Log.i("TAG SET", "Name: " + name + ", value: " + value + ", target " + target);
            }
        }
    };
    
    /*
     * Get all tags associated with the current device and namespace
     */
    public GetAllTagsTask getAllTags(String addr) {
        GetAllTagsTask task = new GetAllTagsTask();
        task.execute(addr);
        return task;
    }
    
    /**
     * Async Task for retrieving all tags associated with the current device and namespace
     */
    class GetAllTagsTask extends AsyncTask<String, Void, Exception> {
    	String deviceAddr;
    	Tag[] tags;

        @Override
        protected Exception doInBackground(String... params) {
        	deviceAddr = params[0];
        	
        	tags = null;        	
            Exception e = null;
            try {
            	tags = m_remote.getTagRemote().get(Tag.TAG_ANY, deviceAddr);
            } catch (Exception ex) {
                e = ex;
            }
            return e;
        }

        protected void onPostExecute(Exception e) {        	
            if (e == null) {                
            	if(tags != null && tags.length != 0){
                	String t = "";
                    for(Tag tag: tags){
                    	if(tag.getName().contains("OwnerName")){
                    		user_name = tag.getValue();
//                    		Toast.makeText(getApplicationContext(), "HELLO, "+tag.getValue(),
//                                    Toast.LENGTH_LONG).show();
                    		
                    		showDialog(DIALOG_GREETING);
                    		
                    		 new CountDownTimer(30000, 1000) {
                    		     public void onTick(long millisUntilFinished) {                    		         
                    		     }

                    		     public void onFinish() {
                    		    	 dismissDialog(DIALOG_GREETING);
                    		     }
                    		  }.start();
                    	}
                        StringBuffer sb = new StringBuffer("tag[").append(tag.getName()).append("]=");
                        sb.append(tag.getValue());                        
                        t += sb.toString();
                        
                        // TODO: greet user
                    }
                    Log.d("Tags", t);
                }
            }
        }
    };
    
    /*
     * Delete all tags associated with the current device and namespace
     */
    public DeleteAllTagsTask deleteAllTags() {
        DeleteAllTagsTask task = new DeleteAllTagsTask();
        task.execute();
        return task;
    }    
    
    /**
     * Async Task for deleting all tags associated with the current device and namespace
     */
    class DeleteAllTagsTask extends AsyncTask<String, Void, Exception> {
    	Tag[] tags;

        @Override
        protected Exception doInBackground(String... params) {
        	tags = null;        	
            Exception e = null;
            try {
            	tags = m_remote.getTagRemote().get(Tag.TAG_ANY, getAddress());
            } catch (Exception ex) {
                e = ex;
            }
            return e;
        }

        protected void onPostExecute(Exception e) {
            if (e == null) {                
            	if(tags != null && tags.length != 0){
                    for(Tag tag: tags){
                    	Log.i("DELETE", "Deleting tag name: " + tag.m_name + ", value: " + tag.m_value);
                        try {
        					m_remote.getTagRemote().delete(tag);
        				} catch (ParseException ex) {
        					Log.i("DELETE", "Delete tag error " + ex);
        				} catch (IOException ex) {
        					Log.i("DELETE", "Delete tag error " + ex);
        				}
                    }
                }
            }
        }
    };
    
    /**
     * scan the neighbourhood
     */
    protected void setDiscoverable() {
        m_localsocial.getNeighbourhood().setDiscoverable();
    }
    
    
    /**
     * Class RemoteDeviseTask
     */    
    class RemoteDeviceTask extends  AsyncTask<String, String, Exception> {

        @Override
        protected Exception doInBackground(String... addresses) {
            Exception e = null;
            
            try {
                for(String address: addresses) {
                    RemoteDevice device = m_devices .get(address);
                    if(device == null) {
                        device = m_remote.getDeviceRemote().getDevice(address);
                        m_devices.put(address,device);
                    }
                }
            } catch (Exception ex) {
                publishProgress("Unexpected Exception : " + ex.getMessage());
                e = ex;
            }
            return e;
        }
    };
    
    
    /**
     * Get the LocalSocial NeighbourhoodObserver
     * 
     * @return the NeighbourhoodObserver
     */
    protected NeighbourhoodObserver getNeighbourhoodObserver() {
        return m_nobby;
    }
    
    NeighbourhoodObserver m_nobby = new NeighbourhoodObserver() {

        @Override
        public void discovered(Device device) {
            String address = device.getAddress();
            if (!m_seen.containsKey(address)) {
                m_seen.put(address, device);
            }
                        
            deviceFound(device);
        }

        @Override
        public void inRange(Device device) {
        	Log.i("NOBBY", "Device in range");
        }
        
        @Override
        public void outOfRange(Device device) {
        	Log.i("NOBBY", "Device out of range");
        }

        @Override
        public void scanStarted(boolean first) {
        	Log.i("NOBBY", "Scan started");
        }

        @Override
        public void scanStopped(int result) {
        	Log.i("NOBBY", "Scan stopped");
        }

		@Override
		public void scanModeChanged(int arg0) {
			Log.i("NOBBY", "Scan mode changed");
		}
        
    };
	
	/**
	 * Check if a device is connected to a network
	 */
	public boolean isOnline() {
		ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
		if (cm.getActiveNetworkInfo() != null) {
			return cm.getActiveNetworkInfo().isConnectedOrConnecting();
		}		
		return false;
	}
	
	/**
	 * InjectKeys
	 * @param keyEventCode
	 */
	private void InjectKeys(final int keyEventCode) {
		 new Thread(new Runnable() {
		  @Override
		  public void run() {
		   new Instrumentation().sendKeyDownUpSync(keyEventCode);
		  }
		 }).start();
	}
	
    /**
     * When a menu item is clicked
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {           
            case R.id.make_discoverable:
            	Intent discoverableIntent = new
            	Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
            	discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
            	startActivity(discoverableIntent);
            	break;
            case R.id.change_user:
            	clearLinkedInCredentials();
            	showDialog(DIALOG_LINKEDIN_OAUTH);
            	break;
        }
        return true;
    }
	
    // The Handler that gets information back from the BluetoothService
    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case MESSAGE_STATE_CHANGE:
                if(D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
                switch (msg.arg1) {
                case BluetoothService.STATE_CONNECTED:
                    break;
                case BluetoothService.STATE_CONNECTING:
                case BluetoothService.STATE_LISTEN:
                case BluetoothService.STATE_NONE:
                    break;
                }
                break;
            case MESSAGE_WRITE:
                byte[] writeBuf = (byte[]) msg.obj;
                // construct a string from the buffer
                String writeMessage = new String(writeBuf);
                Toast.makeText(getApplicationContext(), writeMessage,
                        Toast.LENGTH_SHORT).show();
                break;
            case MESSAGE_READ:
            	Log.d("UserCall", "Message read");
                byte[] readBuf = (byte[]) msg.obj;
                // construct a string from the valid bytes in the buffer
                String readMessage = new String(readBuf, 0, msg.arg1);
                if (readMessage.startsWith("OAUTH:")){                	
                	//dismissDialog(DIALOG_GREETING);
                	
                	String[] ms = readMessage.split(":");
                	Log.d("UserCall", ms[0]+":"+ms[1]+":"+ms[2]);
                	Log.d("UserCall", "user connections: " + user_connections.size());
                	if (user_connections.size() == 0) {	                	
	                	// replace the token
	        			//replaceAuthToken(ms[1], ms[2]);
                		setUserToken(ms[1], ms[2]);
	        			makeUserAPICall();
	        			retrievePossibleConnections();
	        			//Log.d("Stuff", ms[0]+":"+ms[1]+":"+ms[2]);
	        			// change token and secret back
	        			
//	        			try {
//							Thread.sleep(3000);
//						} catch (InterruptedException e) {
//							// TODO Auto-generated catch block
//							e.printStackTrace();
//						}
//	        			
//	        			String token = prefs.getString("token","");
//	        			String secret = prefs.getString("secret","");
//	        			replaceAuthToken(token, secret);
	        			//
                	}
                } else if (readMessage.equals("employees")){
                	display("employees");
                } else if (readMessage.equals("connections")){
                	display("connections");
                } else if (readMessage.equals("possibleConnections")){
                	display("possibleConnections");
                } else if (readMessage.equals("down")){
                	Log.i("Stuff","Before Keypress Down");
                	InjectKeys(KeyEvent.KEYCODE_DPAD_DOWN);
                	Log.i("Stuff","After Keypress Down");
                } else if (readMessage.equals("up")){
                	InjectKeys(KeyEvent.KEYCODE_DPAD_UP);
                } else if (readMessage.equals("left")){
                	InjectKeys(KeyEvent.KEYCODE_DPAD_LEFT);
                } else if (readMessage.equals("right")){
                	InjectKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
                } else if (readMessage.equals("select")){
                	InjectKeys(KeyEvent.KEYCODE_DPAD_CENTER);
                }
//                Toast.makeText(getApplicationContext(), readMessage,
//                        Toast.LENGTH_SHORT).show();
                break;
            case MESSAGE_DEVICE_NAME:
                // save the connected device's name
                Toast.makeText(getApplicationContext(), "Connected to "
                               + msg.getData().getString(DEVICE_NAME), Toast.LENGTH_SHORT).show();
                break;
            case MESSAGE_TOAST:
                Toast.makeText(getApplicationContext(), msg.getData().getString(TOAST),
                               Toast.LENGTH_SHORT).show();
                break;
            }
        }
    };
    
    
    /**
     * Replace the token
     */
    public void replaceAuthToken(String token, String secret) {
    	final Editor edit = prefs.edit();
		edit.putString(OAuth.OAUTH_TOKEN, token);
		edit.putString(OAuth.OAUTH_TOKEN_SECRET, secret);
		edit.commit();
    }
    
    public void setUserToken(String token, String secret) {
    	final Editor edit = prefs.edit();
		edit.putString("user_token", token);
		edit.putString("user_secret", secret);
		edit.commit();
    }
    
    /**
     * Make an API call on behalf of a user
     */
    public void makeUserAPICall() {
    	
    	LinkedInAPICall user_linkedIn = new LinkedInAPICall(this, "user");
    	
    	String jsonOutput = user_linkedIn.execute(Constants.CONNECTIONS_REQUEST);
    	Log.d("UserCall", "Another call");
    	
    	try {
    		Log.d("PERSON", jsonOutput);
    		
			// json object creation
			JSONObject json = new JSONObject(jsonOutput);
			// json parsing
			JSONArray nameArray = json.names();
			JSONArray valArray = json.toJSONArray(nameArray);			
			
			JSONArray connections = valArray.getJSONArray(1);
			// for each person
			for (int i=0; i< connections.length(); i++) {				
				JSONObject object = (JSONObject) new JSONTokener(connections.getString(i)).nextValue();
				String id = object.getString("id");
				String firstName = object.getString("firstName");
				String lastName = object.getString("lastName");			
				String pictureUrl = "";
				try {
					 pictureUrl = object.getString("pictureUrl");
				} catch (Exception noProfilePic) {
					pictureUrl = "noPicture";
				}
				
				Person person = new Person(id, firstName, lastName, pictureUrl);
				user_connections.add(person);
				Log.i("PERSON", "User's " + person.toString());
				//Log.d("UserCall", "url = "+person.getPictureUrl());
			}			
		} catch (JSONException e) {
			Log.d("JSON", "Error creating json object");
			showDialog(DIALOG_LINKEDIN_AUTH_ERROR);
			Log.e(TAG, "Error creating json object",e);
		}
		
    }
    
    public void retrievePossibleConnections() {    	
    	LinkedInAPICall user_linkedIn = new LinkedInAPICall(this, "user");
    	
    	Iterator<Person> it = people.iterator();
    	while (it.hasNext()) {   		
    		Person curr = it.next();
    		
    		String request = Constants.PROFILE_REQUEST 
    		+ curr.getID() + Constants.PROFILE_DIST;
    
    		String jsonOutput = user_linkedIn.execute(request);
    		
    		Log.d("UserCall", "output = " + jsonOutput);
    		
    		try {
				JSONObject json = new JSONObject(jsonOutput);
				String distance = json.getString("relationToViewer");
				
				JSONObject jsonDist = (JSONObject) new JSONTokener(distance).nextValue();
				String distToViewer = jsonDist.getString("distance");
			
				//Log.d("UserCall", curr.getFirstName() + " distance = " + distToViewer);
				
				if (distToViewer.equals("2") || distToViewer.equals("3")) {
					possible_connections.add(curr);
				}
			} catch (JSONException e) {
				Log.e("UserCall", e.toString());
			}
    		
    		
    	}
    }
    
    public void display (String mode) {
    	to_display = new LinkedList<Person>();
		
		if (mode.equals("employees")){
			Log.d("UserCall", "Employees");
			to_display = people;
		} else if (mode.equals("connections")) {
			Log.d("UserCall", "Connections");
			Log.d("UserCall", "People = " + people.size());
			Log.d("UserCall", "User's = " + user_connections.size());
			List<String> ids = new LinkedList<String>();
			Iterator<Person> it = people.iterator();
			while (it.hasNext()) {
				ids.add(it.next().getID());
			}
						
			it = user_connections.iterator();
			while (it.hasNext()) {
				Person curr = it.next();
				if (ids.contains(curr.getID())){
					to_display.add(curr);
				}
			}			
		} else if (mode.equals("possibleConnections")) {
			to_display = possible_connections;
			Log.d("UserCall", "Possible");
		}
					
		grid_view = (GridView) findViewById(R.id.grid_view);
    	image_adapter = new ImageAdapter(this, to_display);
    	grid_view.setAdapter(image_adapter);
    	
    	/**
    	 * OnItemClickListener for grid view
    	 */
    	grid_view.setOnItemClickListener(new OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
                // Toast.makeText(ScreenPhone.this, "Selected position: " + position, Toast.LENGTH_SHORT).show();
            	
                String selectedProfileRequest = Constants.PROFILE_REQUEST 
                		+ to_display.get(position).getID() + Constants.PROFILE_FIELDS;
                
                String jsonOutput = linkedIn.execute(selectedProfileRequest);                
                Log.d("Profile", "json = " + jsonOutput);
                parseJsonProfile(jsonOutput);
                
                if (!curr_view.equals("web")) {
                	switcher.showNext();
                	curr_view = "web";
                }
            }
        });    	
    }
    
    /**
     * Clear the LinkedIn credentials saved in shared preferences
     */
    public void clearLinkedInCredentials() {
		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
		final Editor edit = prefs.edit();
		edit.remove(OAuth.OAUTH_TOKEN);
		edit.remove(OAuth.OAUTH_TOKEN_SECRET);
		edit.commit();
	}
}